#include "tableFlipper.h"

stu_t** alloc2DArray(int m, int n)
{
    stu_t **mat = (stu_t**)calloc(m,sizeof(stu_t*));
    for(int i = 0; i < m; i++)mat[i] = calloc(n, sizeof(stu_t));
    for(int x = 0; x < m; x++){
    	for(int y = 0; y < n; y++){
    		mat[x][y].rank = -1;
    	}
    }
    return mat;
}

int scsanf(char* t, char* s)
{
    if(isu(*s))s++;
    int i;
    for(i = 0,t[i] = s[i]; s[i] != '\t' && s[i] != '\n' && s[i] != ' ';i++, t[i] = s[i]);
    t[i] = '\0';
    return i;
}

cpny_t* cinit(char *filename)
{
    cpny_t* cpny = (cpny_t*)malloc(sizeof(cpny_t));
	char* data = cinput(filename);
    clean(data);
	det(data, cpny);
    cpny->matrix = alloc2DArray(cpny->column, cpny->row);
	for(int x = 0, y = cpny -> row - 1; *data != '\0'; ){
		while(iss(*data)){
			data++;
			x++;
		}
		if(isn(*data)){
			y--;
			x = 0;
			data++;
		}
        if(y < 0)break;
        (cpny->matrix)[x][y].name = (char*)calloc(16, sizeof(char));
        data += scsanf((cpny->matrix)[x][y].name, data);
        (cpny->matrix)[x][y].rank = 1;
	}
    return cpny;
}

char* cinput(char* filename)
{
	int fd = open(filename,O_RDONLY,0);
    if(fd < 0){
        fprintf(stderr, "Failed to read file!\nExiting...");
#ifdef WINDOWS
        system("PAUSE");
#endif
        exit(0);
    }
	struct stat filestat;
	fstat(fd, &filestat);
	char* buf = (char*)calloc(filestat.st_size + 1,sizeof(char));
	buf[read(fd, buf, filestat.st_size)] = '\0';
    close(fd);
	return buf;
}

void cdealloc(cpny_t* cpny)
{
	int column = cpny -> column, row = cpny -> row;
	for(int x = column - 1; x >= column; x--)
	{
		for(int y = 0; y < row; y++)
        {
            free((cpny -> matrix)[x][y].name);
        }//sdealloc(&(cpny -> matrix)[x][y]);
		free((cpny -> matrix)[x]);
	}
	free(cpny);
}

void clean(char* buf)
{
    while(*(++buf + 1) != '\0');
    while(*--buf == '\n');
    buf[1] = '\n';
    buf[2] = '\0';
}

void det(char* data, cpny_t* cpny)
{
	cpny -> row = 0;
	cpny -> column = 0;
	for(int x = 1; *data != '\0'; data++){
        if(*data == '\t' || *data == ' ')x++;
		else if(*data == '\n'){
			cpny -> row++;
			cpny -> column = (cpny -> column < x) ? x : cpny -> column;
			x = 1;
		}
	}
}

void cdisplay(int column, int row, FILE* fp, cpny_t* cpny)
{
	fprintf(fp, "column = %d\trow = %d\n", column, row);
    for(int y = row - 1; y >= 0; y--)
    {
        for(int x = 0; x < column; x++)
        {
            if((cpny -> matrix)[x][y].rank < 0)putc('\t',fp);
			else fprintf(fp, "%s\t",(cpny -> matrix)[x][y].name);
        }
        putchar('\n');
    }
}

#pragma mark TODO: Simplify the code of shifting and coordinate converting.

void cshl(cpny_t* cpny)
{
	int column = cpny -> column, row = cpny -> row;
	pos_t first, second;
	for(int y = 0; y < row; y++)
	{
		for(int x = 1; x < column; x++)
		{
			first.x = x;
			first.y = y;
			second.x = x - 1;
			second.y = y;
			cswap(cpny, first, second);
		}
	}
}

void cshr(cpny_t* cpny)
{
	int column = cpny -> column, row = cpny -> row;
	pos_t first, second;
	for(int y = 0; y < row; y++)
	{
		for(int x = column - 1; x > 0; x--)
		{
			first.x = x;
			first.y = y;
			second.x = x - 1;
			second.y = y;
			cswap(cpny, first, second);
		}
	}
}

void cshu(cpny_t* cpny)
{
	int column = cpny -> column, row = cpny -> row;
	pos_t first, second;
	for(int x = 0; x < column; x++)
	{
		for(int y = 1; y < row; y++)
		{
			first.x = x;
			first.y = y;
			second.x = x;
			second.y = y - 1;
			if((cpny->matrix)[x][y].rank > 0)cswap(cpny, first, second);
		}
	}
}

void cshd(cpny_t* cpny)
{
	int column = cpny -> column, row = cpny -> row;
	pos_t first, second;
	for(int x = 0; x < column; x++)
	{
		for(int y = row - 1; y > 0; y--)
		{
			first.x = x;
			first.y = y;
			second.x = x;
			second.y = y - 1;
			if((cpny->matrix)[x][y].rank > 0)cswap(cpny, first, second);
		}
	}
}

void revertX(cpny_t* cpny)
{
    int column = cpny -> column, row  = cpny -> row;
    pos_t first, second;
    for(int x = 0; x < column / 2; x++)
    {
        for(int y = 0; y < row; y++)
        {
            first.x = x;
            first.y = y;
            second.x = column - x - 1;
            second.y = y;
            cswap(cpny, first, second);
        }
    }
}

void revertY(cpny_t* cpny)
{
    int column = cpny -> column, row  = cpny -> row;
    pos_t first, second;
    for(int y = 0; y < row / 2; y++)
    {
        for(int x = 0; x < column; x++)
        {
            first.x = x;
            first.y = y;
            second.x = x;
            second.y = row - y - 1;
            cswap(cpny, first, second);
        }
    }
}

void cswap(cpny_t* cpny,pos_t first,pos_t second)
{
	stu_t temp = (cpny->matrix)[first.x][first.y];
	(cpny->matrix)[first.x][first.y] = (cpny->matrix)[second.x][second.y];
	(cpny->matrix)[second.x][second.y] = temp;
}

void crnd(cpny_t* cpny)
{
    int column = cpny->column, row = cpny->row;
    pos_t first, second;
    srand((unsigned)time(0));
    for(int i = 0; i < 1000; i++){
        first.x = RAND(0, column - 1);
        first.y = RAND(0, row - 1);
        second.x = RAND(0, column - 1);
        second.y = RAND(0, row - 1);
        cswap(cpny, first, second);
    }
}